package com.geccocrawler.gecco.spider.render;

import com.geccocrawler.gecco.annotation.FieldRenderName;
import com.geccocrawler.gecco.annotation.Href;
import com.geccocrawler.gecco.request.HttpRequest;
import com.geccocrawler.gecco.response.HttpResponse;
import com.geccocrawler.gecco.scheduler.DeriveSchedulerContext;
import com.geccocrawler.gecco.spider.SpiderBean;
import com.geccocrawler.gecco.utils.ReflectUtils;
import net.sf.cglib.beans.BeanMap;
import org.apache.commons.lang3.StringUtils;
import org.reflections.ReflectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Set;

/**
 * render抽象方法，主要包括注入基本的属性和自定义属性注入。将特定的html、json、xml注入放入实现类
 *
 * @author huchengyi
 */
public abstract class AbstractRender implements Render {

    private static Logger log = LoggerFactory.getLogger(AbstractRender.class);

    /**
     * request请求的注入
     */
    private RequestFieldRender requestFieldRender;

    /**
     * request参数的注入
     */
    private RequestParameterFieldRender requestParameterFieldRender;
    /**
     * requesturl的参数注入
     */
    private RequestUrlFieldRender requestUrlFieldRender;

    /**
     * response响应的注入
     */
    private ResponseFieldRender responseFieldRender;
    /**
     * responseBody的响应字符串注入
     */
    private ResponseBodyFieldRender responseBodyFieldRender;
    /**
     * 静态常亮的注入，主要是Dynamic的时候使用
     */
    private ConstantValueFieldRender constantValueFieldRender;

    /**
     * 自定义注入
     */
    private CustomFieldRenderFactory customFieldRenderFactory;

    public AbstractRender() {
        this.requestFieldRender = new RequestFieldRender();
        this.requestParameterFieldRender = new RequestParameterFieldRender();
        this.requestUrlFieldRender = new RequestUrlFieldRender();
        this.responseFieldRender = new ResponseFieldRender();
        this.responseBodyFieldRender = new ResponseBodyFieldRender();
        this.constantValueFieldRender = new ConstantValueFieldRender();
    }

    @Override
    @SuppressWarnings({"unchecked"})
    public SpiderBean inject(Class<? extends SpiderBean> clazz, HttpRequest request, HttpResponse response) {
        try {
            SpiderBean bean = clazz.newInstance();
            BeanMap beanMap = BeanMap.create(bean);
            requestFieldRender.render(request, response, beanMap, bean);
            requestParameterFieldRender.render(request, response, beanMap, bean);
            requestUrlFieldRender.render(request, response, beanMap, bean);
            responseBodyFieldRender.render(request, response, beanMap, bean);
            responseFieldRender.render(request, response, beanMap, bean);
            constantValueFieldRender.render(request, response, beanMap, bean);
            fieldRender(request, response, beanMap, bean);
            Set<Field> customFields = ReflectionUtils.getAllFields(bean.getClass(), ReflectionUtils.withAnnotation(FieldRenderName.class));
            for (Field customField : customFields) {
                FieldRenderName fieldRender = customField.getAnnotation(FieldRenderName.class);
                String name = fieldRender.value();
                CustomFieldRender customFieldRender = customFieldRenderFactory.getCustomFieldRender(name);
                if (customFieldRender != null)
                    customFieldRender.render(request, response, beanMap, bean, customField);
            }
            requests(request, bean);
            return bean;
        } catch (Exception ex) {
            log.error("instance SpiderBean error", ex);
            return null;
        }
    }

    public abstract void fieldRender(HttpRequest request, HttpResponse response, BeanMap beanMap, SpiderBean bean);

    /**
     * 需要继续抓取的请求
     */
    @Override
    @SuppressWarnings({"unchecked"})
    public void requests(HttpRequest request, SpiderBean bean) {
        BeanMap beanMap = BeanMap.create(bean);
        Set<Field> hrefFields = ReflectionUtils.getAllFields(bean.getClass(),
                ReflectionUtils.withAnnotation(Href.class));
        for (Field hrefField : hrefFields) {
            Href href = hrefField.getAnnotation(Href.class);
            if (href.click()) {
                Object o = beanMap.get(hrefField.getName());
                if (o == null)
                    continue;
                boolean isList = ReflectUtils.haveSuperType(o.getClass(), List.class);// 是List类型
                if (isList) {
                    List<?> list = (List<?>) o;
                    for (Object url : list)
                        if (url != null && StringUtils.isNotEmpty(String.valueOf(url)))
                            DeriveSchedulerContext.into(request.subRequest(String.valueOf(url)));
                } else if (o.getClass().isArray()) {
                    Object[] objs = (Object[]) o;
                    for (Object obj : objs)
                        DeriveSchedulerContext.into(request.subRequest(String.valueOf(obj)));
                } else {
                    String url = String.valueOf(o);
                    if (StringUtils.isNotEmpty(url))
                        DeriveSchedulerContext.into(request.subRequest(url));
                }
            }
        }
    }

    public void setCustomFieldRenderFactory(CustomFieldRenderFactory customFieldRenderFactory) {
        this.customFieldRenderFactory = customFieldRenderFactory;
    }

}
